﻿using System;
using System.Diagnostics;
using System.IO;

namespace SfsTools.Core
{
    /// <summary>
    /// Represents the root directory on the <see cref="FileSystem"/>.
    /// </summary>
    internal class RootDirectory : Directory, IDirectory
    {
        #region Properties

        #endregion

        #region Methods

        /// <summary>
        /// Renames this <see cref="IFileSystemObject"/> to <paramref name="name"/>.
        /// </summary>
        /// <param name="name">The new name of this <see cref="IFileSystemObject"/>.</param>
        /// <exception cref="ArgumentNullException">The argument <paramref name="name"/> is <see langword="null"/>.</exception>
        /// <exception cref="ArgumentException">The argument <paramref name="name"/> contains invalid characters.</exception>
        /// <exception cref="InvalidOperationException">The parent directory already contains a <see cref="IFileSystemObject"/> with <paramref name="name"/>.</exception>
        /// <exception cref="IndexAreaFullException">Cannot allocate entries because the index area is full.</exception>
        /// <exception cref="System.IO.PathTooLongException">The full path is too long.</exception>
        /// <exception cref="System.IO.IOException">An I/O exception occurred.</exception>
        [DebuggerStepThrough]
        public override void Rename(String name)
        {
            if (name == null)
                throw new ArgumentNullException("name");
            // The root can never be renamed.
            throw new CannotRenameRootDirectoryException();
        }

        /// <summary>
        /// Deletes this <see cref="IFileSystemObject"/>.
        /// </summary>
        /// <exception cref="InvalidOperationException">The <see cref="IFileSystemObject"/> is already deleted.</exception>
        /// <exception cref="System.IO.IOException">An I/O exception occurred.</exception>
        [DebuggerStepThrough]
        public override void Delete()
        {
            // The root can never be deleted.
            throw new CannotDeleteRootDirectoryException();
        }

        /// <summary>
        /// Restores this <see cref="IFileSystemObject"/> that was previously deleted.
        /// </summary>
        /// <exception cref="InvalidOperationException">The <see cref="IFileSystemObject"/> is not deleted.</exception>
        /// <exception cref="System.IO.IOException">An I/O exception occurred.</exception>
        /// <exception cref="IndexAreaFullException">Cannot create <see cref="IFileSystemObject"/> because the index area is full.</exception>
        [DebuggerStepThrough]
        public override void Resurrect()
        {
            // Since the root can never be deleted, you cant resurrect it either.
            throw new CannotResurrectRootDirectoryException();
        }

        #endregion

        #region Constructors
        /// <overloads>Initializes a new instance of <see cref="RootDirectory"/>.</overloads>
        /// <summary>
        /// Initializes a new instance of <see cref="RootDirectory"/>.
        /// </summary>
        /// <param name="fs">The file system.</param>
        [DebuggerStepThrough]
        public RootDirectory(FileSystem fs)
            : base(fs)
        {
        }
        #endregion

        #region IDirectory Members

        /// <summary>
        /// Resolves the specified path to a <see cref="IFileSystemObject"/>.
        /// </summary>
        /// <param name="name">The relative or absolute path to resolve.</param>
        /// <returns>The <see cref="IFileSystemObject"/> specified by <paramref name="name"/>.</returns>
        /// <exception cref="ArgumentNullException">The argument <paramref name="name"/> is <see langword="null"/>.</exception>
        /// <exception cref="PathNotFoundException">The specified <see cref="IFileSystemObject"/> cannot be found.</exception>
        [DebuggerStepThrough]
        IFileSystemObject IDirectory.Resolve(String name)
        {
            return Resolve(name);
        }

        /// <summary>
        /// Returns an array containing all <see cref="IDirectory">subdirectories</see>.
        /// </summary>
        /// <returns>An array containing all <see cref="IDirectory">subdirectories</see>.</returns>
        [DebuggerStepThrough]
        IDirectory[] IDirectory.GetDirectories()
        {
            return GetDirectories();
        }

        /// <summary>
        /// Returns an array containing all <see cref="IDirectory">subdirectories</see>.
        /// </summary>
        /// <param name="includeDeleted">Specifies whether to include deleted directories as well.</param>
        /// <returns>An array containing all <see cref="IDirectory">subdirectories</see>.</returns>
        [DebuggerStepThrough]
        IDirectory[] IDirectory.GetDirectories(bool includeDeleted)
        {
            return GetDirectories(includeDeleted);
        }

        /// <summary>
        /// Returns an array containing all <see cref="IFile"/>s.
        /// </summary>
        /// <returns>An array containing all <see cref="IFile"/>s.</returns>
        [DebuggerStepThrough]
        IFile[] IDirectory.GetFiles()
        {
            return GetFiles();
        }

        /// <summary>
        /// Returns an array containing all <see cref="IFile"/>s.
        /// </summary>
        /// <param name="includeDeleted">Specifies whether to include deleted <see cref="IFile"/>s as well.</param>
        /// <returns>An array containing all <see cref="IFile"/>s.</returns>
        [DebuggerStepThrough]
        IFile[] IDirectory.GetFiles(bool includeDeleted)
        {
            return GetFiles(includeDeleted);
        }

        /// <summary>
        /// Returns an array containing all <see cref="IFileSystemObject"/>s.
        /// </summary>
        /// <returns>An array containing all <see cref="IFileSystemObject"/>s.</returns>
        [DebuggerStepThrough]
        IFileSystemObject[] IDirectory.GetObjects()
        {
            return GetObjects();
        }

        /// <summary>
        /// Returns an array containing all <see cref="IFileSystemObject"/>s.
        /// </summary>
        /// <param name="includeDeleted">Specifies whether to include deleted <see cref="IFileSystemObject"/>s as well.</param>
        /// <returns>An array containing all <see cref="IFileSystemObject"/>s.</returns>
        [DebuggerStepThrough]
        IFileSystemObject[] IDirectory.GetObjects(bool includeDeleted)
        {
            return GetObjects(includeDeleted);
        }

        /// <summary>
        /// Creates a subdirectory.
        /// </summary>
        /// <param name="name">The name of the subdirectory.</param>
        /// <returns>An <see cref="IDirectory"/> instance representing the subdirectory.</returns>
        /// <exception cref="ArgumentNullException">The argument <paramref name="name"/> is <see langword="null"/>.</exception>
        /// <exception cref="ArgumentException">The argument <paramref name="name"/> contains invalid characters.</exception>
        /// <exception cref="IndexAreaFullException">Cannot create directory because the index area is full.</exception>
        /// <exception cref="System.IO.PathTooLongException">The full path is too long.</exception>
        /// <exception cref="System.IO.IOException">An I/O exception occurred.</exception>
        [DebuggerStepThrough]
        IDirectory IDirectory.CreateDirectory(String name)
        {
            return CreateDirectory(name);
        }

        /// <overloads>Creates or overwrites a file.</overloads>
        /// <summary>
        /// Creates or overwrites a file.
        /// </summary>
        /// <param name="name">The name of the file.</param>
        /// <returns>An <see cref="IFile"/> instance representing the subdirectory.</returns>
        /// <exception cref="ArgumentNullException">The argument <paramref name="name"/> is <see langword="null"/>.</exception>
        /// <exception cref="ArgumentException">The argument <paramref name="name"/> contains invalid characters.</exception>
        /// <exception cref="IndexAreaFullException">Cannot create file because the index area is full.</exception>
        /// <exception cref="System.IO.PathTooLongException">The full path is too long.</exception>
        /// <exception cref="System.IO.IOException">An I/O exception occurred.</exception>
        [DebuggerStepThrough]
        IFile IDirectory.CreateFile(String name)
        {
            return CreateFile(name, -1);
        }

        /// <summary>
        /// Creates or overwrites a file while reserving space for it in the data area.
        /// </summary>
        /// <param name="name">The name of the file.</param>
        /// <param name="length">Specifies the maximum length of the file that is guaranteed to be available.</param>
        /// <returns>An <see cref="IFile"/> instance representing the subdirectory.</returns>
        /// <remarks>The <see cref="IFile"/> can grow larger than <paramref name="length"/>, but that space is not guaranteed to be available.</remarks>
        /// <exception cref="ArgumentNullException">The argument <paramref name="name"/> is <see langword="null"/>.</exception>
        /// <exception cref="ArgumentException">The argument <paramref name="name"/> contains invalid characters.</exception>
        /// <exception cref="ArgumentOutOfRangeException">The argument <paramref name="length"/> is negative.</exception>
        /// <exception cref="IndexAreaFullException">Cannot create file because the index area is full.</exception>
        /// <exception cref="DataAreaFullException">Cannot create file because the data area is full.</exception>
        /// <exception cref="System.IO.PathTooLongException">The full path is too long.</exception>
        /// <exception cref="System.IO.IOException">An I/O exception occurred.</exception>
        [DebuggerStepThrough]
        IFile IDirectory.CreateFile(String name, Int64 length)
        {
            if (length < 0)
                throw new ArgumentOutOfRangeException("length");
            return CreateFile(name, length);
        }

        /// <summary>
        /// Deletes the <see cref="IDirectory"/> with the specified <paramref name="name"/>.
        /// </summary>
        /// <param name="name">The name of the <see cref="IDirectory"/> to delete.</param>
        /// <exception cref="ArgumentNullException">The argument <paramref name="name"/> is <see langword="null"/>.</exception>
        /// <exception cref="IOException">An I/O exception occurred.</exception>
        /// <exception cref="DirectoryNotFoundException">The specified directory cannot be found.</exception>
        [DebuggerStepThrough]
        void IDirectory.Delete(String name)
        {
            Delete(name);
        }

        /// <summary>
        /// Deletes this <see cref="IDirectory"/>.
        /// </summary>
        /// <param name="recurse">Specifies whether to delete any files and subdirectories as well.</param>
        /// <exception cref="InvalidOperationException">The directory is not empty, and <paramref name="recurse"/> was not specified.</exception>
        void IDirectory.Delete(bool recurse)
        {
            if (!recurse)
            {
                // The root can never be deleted.
                throw new CannotDeleteRootDirectoryException();
            }
            else
            {
                foreach (IDirectory directory in GetDirectories())
                {
#if false
                    if (!directory.IsDeleted)
#endif
                        directory.Delete(true);
                }
            }
        }

        /// <summary>
        /// Deletes the <see cref="IDirectory"/> with the specified <paramref name="name"/>.
        /// </summary>
        /// <param name="name">The name of the <see cref="IDirectory"/> to delete.</param>
        /// <param name="recurse">Specifies whether to delete any files and subdirectories as well.</param>
        /// <exception cref="ArgumentNullException">The argument <paramref name="name"/> is <see langword="null"/>.</exception>
        /// <exception cref="IOException">An I/O exception occurred.</exception>
        /// <exception cref="DirectoryNotFoundException">The specified directory cannot be found.</exception>
        /// <exception cref="InvalidOperationException">The directory is not empty, and <paramref name="recurse"/> was not specified.</exception>
        [DebuggerStepThrough]
        void IDirectory.Delete(String name, bool recurse)
        {
            Delete(name, recurse);
        }

#if false
        /// <summary>
        /// Restores this <see cref="IDirectory"/> that was previously deleted.
        /// </summary>
        /// <param name="recurse">Specifies whether to restore any files and subdirectories as well.</param>
        /// <exception cref="InvalidOperationException">The directory is not deleted.</exception>
        /// <exception cref="IOException">An I/O exception occurred.</exception>
        /// <exception cref="IndexAreaFullException">Cannot create directory because the index area is full.</exception>
        void IDirectory.Resurrect(bool recurse)
        {
            if (!recurse)
            {
                // Since the root can never be deleted, you cant resurrect it either.
                throw new CannotResurrectRootDirectoryException();
            }
            else
            {
                foreach (IDirectory directory in GetDirectories())
                {
                    if (directory.IsDeleted)
                        directory.Resurrect(true);
                }
            }
        }
#endif

        #endregion
    }
}
